#pragma once



#include <ImageHlp.h>

#include <vector>
#include <list>
#include <set>



/**
 Manual:

 Project setup:
  - add to stdafx.h (immediatly after MFC or ATL headers)
   #include "Debug.h"

      - add Debug.cpp to the project
     OR
   - #define DEBUG_SINGLE_HEADER (before #include 'debug.h' or in project settings)



 LogFile Configuration:
  Put these things anywhere in your global-scope (e.g. before your "int main(...)")

  // set trace format
  SET_TRACE_OPTS( ALL_TRACE_LEVELS, TraceDbgOutput | TraceSystemTime | TraceFnName );

  // set log-file
  #if defined(_DEBUG)  ||  defined(RELEASE_TRACE)  // prevent log file in release
   SET_TRACE_FILE( ALL_TRACE_LEVELS, "clog.txt", TraceVersionOutput );
  #endif


  (see below for detail description)


  Basic usage:

  TRACE(nLevel, format, ...);
  TRACE(format, ...);   // nLevel = 0

   Debug output. Used like "printf"
   Output string will be formated with a prefix string and a linebreak (by default)

  specials:
   TRACENL  -> only prefix
   TRACENP  -> only linefeed
   TRACENLP -> pure text
   TRACENPL -> pure text
   TRACERB  -> TRACE with rollback enabled

   ELSE_TRACE -> for error messages like:
    if (myfunktion())  AfxMsgBox("it worked");  ELSE_TRACE("it doesn't worked");



  ... to do:
   #define  SET_MAX_TRACE_LEVEL(nLevel)    static dbgTracer__TraceLevelInitializer __dbg_util__li__(nLevel, true)
   #define  SET_ACTIVE_TRACE_LEVEL(nLevel)    static dbgTracer__TraceLevelInitializer __dbg_util__li__(nLevel, false)
   #define  SET_ACTIVE_TRACE_LEVELS(nCount, pLevels) static dbgTracer__TraceLevelInitializer __dbg_util__li__(nCount, pLevels)

   #define  ELSE_TRACE else __dbg_util__dbgTracer.SetTraceInfo(FileLineInfo, __dbg_util::PfLf)->Trace
   #define  REMOVE_LAST_TRACE __dbg_util__dbgTracer.RemoveLastTrace
   #define  TRACESTR __dbg_util__dbgTracer.TraceStr
   #define  TRACESTRP __dbg_util__dbgTracer.SetTraceInfo(FileLineInfo, __dbg_util::Pf)->TraceStrPrefix
   #define  DUMP  __dbg_util__dbgTracer.SetTraceInfo(FileLineInfo, __dbg_util::Pf)->Dump
   #define  DUMPNP  __dbg_util__dbgTracer.SetTraceInfo(FileLineInfo, 0)->Dump
   #define  DUMPTBL __dbg_util__dbgTracer.SetTraceInfo(FileLineInfo, __dbg_util::Pf)->DumpTable

   #define  TRACE_ARGS   __dbg_util__dbgTracer.SetTraceInfo(FileLineInfo, __dbg_util::PfLf | TraceFnArgsStripped)->Trace
   #define  TRACE_ARGS_FULL __dbg_util__dbgTracer.SetTraceInfo(FileLineInfo, __dbg_util::PfLf | TraceFnArgs)->Trace

   #define  TRACE_STACK __dbg_util__dbgTracer.SetTraceInfo(FileLineInfo, __dbg_util::PfLf)->TraceStack
   #define  TRACE_STACKNP __dbg_util__dbgTracer.SetTraceInfo(FileLineInfo, __dbg_util::Lf)->TraceStack

   #define  FLUSH_TRACE_BUFFER(nLevel)  __dbg_util__dbgTracer.FlushTraceBuffer(nLevel);

   // Simple testing routines support
   #define  SET_TESTS_SEPARATOR(strFmt) __dbg_util__dbgTracer.SetTestsSeparator(strFmt)
   #define  RESET_TEST_NUM() __dbg_util__dbgTracer.ResetTestNumber()
   #define  EXPECTED   __dbg_util__dbgTracer.SetTraceInfo(FileLineInfo, 0)->TraceExpected
   #define  RESULTED   __dbg_util__dbgTracer.SetTraceInfo(FileLineInfo, 0)->TraceResulted
   #define  RESULTEDNA   __dbg_util__dbgTracer.SetTraceInfo(FileLineInfo, __dbg_util::DontAssert)->TraceResulted



  Configuration:


**/



//#define DEBUG_SINGLE_HEADER





/**
*
**/
enum  dbgTracer_FileOpts
{
    TraceWriteThrough = 0x01,
    TraceNewLog   = 0x02,
    TraceBackupLog  = 0x04,
    TraceVersionOutput = 0x08,
    TraceOSOutput = 0x10
};



/**
*
**/
enum  dbgTracer_TraceOpts
{
    // Additional information flags
    TraceSystemTime   = 0x01,
    TraceLocation   = 0x02,
    TracePID    = 0x04,
    TraceTID    = 0x08,
    TracePrTime    = 0x10,
    TraceThrTime   = 0x20,
    TraceRealPrThrTime  = 0x40,
    TraceLevel    = 0x80,
    TraceAddInfoMask  = 0xFF,

    // Functions information flags
    TraceFnName    = 0x0100,
    TraceFnArgTypes   = 0x0200,
    TraceFnArgs    = 0x0400,
    TraceFnCallDisp   = 0x0800,
    TraceFnStripTemplArgs = 0x1000,
    TraceFnStripStringArgs = 0x2000,
    TraceFnNoRawWideStrings = 0x4000,
    TraceFnDontUndecorate = 0x8000,
    TraceFnInfoMask   = TraceFnName | TraceFnArgTypes | TraceFnArgs | TraceFnCallDisp | TraceFnStripStringArgs | TraceFnStripTemplArgs | TraceFnDontUndecorate,

    // Representation flags
    TraceMicroseconds = 0x00010000,
    TraceMiliseconds = 0x00020000,
    TraceRtiHex   = 0x00040000,
    TraceFnDecIntArgs = 0x00080000,
    TraceFnHexIntArgs = 0x00100000,
    TraceFnDispHex  = 0x00200000,
    TraceLevelDisp  = 0x00400000,
    TraceFnReprMask  = TraceFnDecIntArgs | TraceFnHexIntArgs | TraceFnDispHex,
    TraceFnMask   = TraceFnInfoMask | TraceFnReprMask,

    // Destination flags
    TraceDbgOutput  = 0x01000000,
    TraceMemBuffer  = 0x02000000,

    // Predefined flag combinations
    TracePrThrID  = TracePID | TraceTID,
    TracePrThrTime  = TracePrTime | TraceThrTime,
    TraceRTI   = TracePrThrID | TracePrThrTime,
    TraceFnArgsStripped = TraceFnArgs | TraceFnStripTemplArgs | TraceFnStripStringArgs,
    TraceFnArgTypesStripped = TraceFnArgTypes | TraceFnStripTemplArgs,
    TraceStdInfo  = TraceDbgOutput | TraceSystemTime | TraceTID | TraceMicroseconds,
    TraceAll   = TraceDbgOutput | TraceSystemTime | TraceLocation | TraceRTI | TraceFnArgs | TraceMicroseconds,
    TraceStdStackInfo = TraceLocation | TraceFnArgsStripped | TraceFnCallDisp
};



enum  dbgTracer_DumpTypes
{
    DumpHex = 0,
    DumpDec = 1,
    DumpRadixMask = 1,

    DumpBytes =  0,
    DumpWords =  2,
    DumpDwords = 4,
    DumpQwords = 6,
    Dump8 =  0,
    Dump16 =  2,
    Dump32 = 4,
    Dump64 = 6,
    DumpElemSizeMask = 0x0E, // 1110

    DumpNoText = 0,
    DumpAscii = 16,
    DumpUnicode = 32,
    DumpTchars = 48,
    DumpTextReprMask = 0x30,  // 0011 0000

    DumpBoundNone = 0,
    DumpBoundBrackets = 64,
    DumpBoundBraces = 128,
    DumpBoundAngleBrackets = 192,
    DumpBoundMask = 0xC0,   // 1100 0000

    DumpDelimSpace = 0,
    DumpDelimComma = 256,
    DumpDelimMask = 0x100
};


#define  ALL_TRACE_LEVELS  (-1)
#define  CRASH_REPORT_LEVEL  (-2)



#if defined(TRACE)
#undef  TRACE
#endif
#if  defined(VERIFY)
#undef  VERIFY
#endif
#if  defined(ASSERT)
#undef  ASSERT
#endif


#if defined(_DEBUG)  ||  defined(RELEASE_TRACE)  ||  !defined(TRACE_NO_CRASH_REPORT)


typedef  void (*COMPUTER_CFG_INFO)(LPTSTR pszBuf);     // The size of pszBuf is 4K.

typedef  void (*CRASHREPORTCALLBACK)(PEXCEPTION_POINTERS pExceptionInfo, HANDLE hRptFile,
                                     LPCTSTR pcszRptFullPath, LPCTSTR pcszRptFileName,
                                     LPCTSTR pcszAppFullPath, LPCTSTR pcszAppFileName);


namespace  __dbg_util
{

enum  TraceFlags
{
    Prefix = 1,
    TrailingLineFeed = 2,
    RollbackInfo = 4,
    Pf = Prefix, Lf = TrailingLineFeed, Rb = RollbackInfo,
    PfLf = Prefix | TrailingLineFeed,
    PfLfRb = Prefix | TrailingLineFeed | RollbackInfo,
    DontAssert = 8,
    ExtraNestingMask = 0xC000
};





class  AFX_EXT_CLASS dbgTracer
{
        //     Because of the bug in STL (incorrect destruction of static containers based on
        // _Tree class), the m_pActiveLevelsSet member is compelled to be a pointer to the 'vector'
        // instead of more convenient 'set' container. This bug could have been worked around by
        // allocating a pointer to the set dynamically and never destroying it. Yet such a technique
        // causes MFC to produce memory leak report in debug builds (global allocator does not
        // help to get rid of the warning). Though this leak is harmless, the warnings are too
        // embarrassing to put up with them.

        typedef  std::list<UINT>  FILE_POS_LIST;
        typedef  std::set<std::string> PATHS_SET;
        typedef  PATHS_SET::iterator PATHS_SET_IT;
        typedef  std::vector<int>  LEVELS_VEC;
        typedef  LEVELS_VEC::iterator LEVELS_VEC_IT;

        //     m_hMutex:
        // Used to reveal whether symbolic info has already been initialized for the current process
        HANDLE  m_hMutex;

        //     m_iLevel, m_pszFile, m_dwLine, m_dwTraceFlags:
        //     These members are set by the SetTraceInfo method (which is called by TRACE and
        // DUMP macros) to route this information to the Trace and Dump methods correspondingly.
        int   m_iLevel;
        LPTSTR  m_pszFile;
        DWORD  m_dwLine;
        DWORD  m_dwTraceFlags;

        int     *m_pnMaxLevel, *m_pnActiveLevel;
        LEVELS_VEC   *m_pActiveLevelsSet;

        //     m_pdwOpts, m_phRptFiles, m_pFilePosLists:
        //     These members point to the arrays of objects, which elements contain settings
        // associated with corresponding trace level. The settings for the CRASH_REPORT_LEVEL
        // are kept in the next group of members.
        DWORD   *m_pdwOpts;
        HANDLE   *m_phRptFiles;
        FILE_POS_LIST *m_pFilePosLists;

        //     m_pdwCrashRptOpts, m_pdwCrashRptFileOpts, m_phCrashRptFile, m_pszCrashRptFile:
        //     Crash report related info (CRASH_REPORT_LEVEL). The file name is stored in order
        // to open the report file only when a fault occur. This prevents the previous crash
        // report from being instantly erased by the next run of the program, because by default
        // *m_pdwCrashRptOpts contains TraceNewLog flag.
        DWORD   *m_pdwCrashRptOpts,
        *m_pdwCrashRptFileOpts;
        LPTSTR   m_pszCrashRptFile;
        HANDLE   *m_phCrashRptFile;

        //     m_pfnComputerCfgInfo, m_pfnCrashRptCallback:
        //     Callback functions that can be registered by the application to extend crash
        // reporting capabilities.
        COMPUTER_CFG_INFO  *m_pfnComputerCfgInfo;
        CRASHREPORTCALLBACK  *m_pfnCrashRptCallback;

        __int64   m_i64PerfFreq,
        m_i64PerfCntAmendment, m_i64PerfCntAmendmentUTC;
        SYSTEMTIME  m_stCurrent;

        DWORD  *m_pnObjects;

        LPTSTR  *m_ppszBuffer;
        long  *m_pnBufferSize,
        *m_pnBufferCurPos,
        *m_pnBufferDeadLine,
        *m_pnBufferEnd;

        long  *m_pnExtraNesting,
        *m_pnPrepareFmtStringExtraNesting;

        DWORD  *m_pdwStackTraceOpts;

        DWORD  *m_pnTestNumber;
        LPTSTR  m_pszTestsSeparatorFmt;


        LPTSTR  GetExpectedBuf();
        LPTSTR  GetResultedBuf();

        __int64  GetTimes(FILETIME& ftCreationTime, FILETIME& ftKernelMode, FILETIME& ftUserMode, __int64& dwSec, __int64& dwMilliSec, __int64& dwMicroSec, bool bReal);
        __int64  GetCurThreadTime(__int64& dwSec, __int64& dwMilliSec, __int64& dwMicroSec, bool bReal);
        __int64  GetCurProcessTime(__int64& dwSec, __int64& dwMilliSec, __int64& dwMicroSec, bool bReal);

        DWORD  RemoveTrailingNewline(LPTSTR pszMsg);
        void  AddTrailingNewline(LPTSTR pszMsg);

        void  DumpData(LPTSTR pszMsg, PVOID pvData, DWORD dwDataSize, DWORD dwParams, DWORD nAbsentElems);

        DWORD  GetParams(int nLevel, PHANDLE phFile = NULL, FILE_POS_LIST** ppfpl = NULL);

        void  PrepareFmtString(int nLevel, LPTSTR pszFmt, LPCTSTR pcszSrcFmt, DWORD dwForceFnInfo = 0, DWORD dwForceOpts = -1);
        void  OutputMsgToMemBuffer(LPCTSTR pszMsg, long nMsgSize);
        void  OutputMsgToFile(int nLevel, LPCTSTR pszMsg, long nMsgSize, bool bSetRollbackInfo);
        void  OutputMsg(int nLevel, LPCTSTR pszMsg, bool bSetRollbackInfo = false);

        static  void  OpenRptFile(HANDLE *phFile, LPCTSTR pcszFile, DWORD dwFileOpts);

        void  InternalDump(int nLevel, LPTSTR pszMsg, PVOID pvData, DWORD dwDataSize, DWORD dwParams, LPCTSTR pcszFmt, va_list argptr);
        void  InternalDumpTable(int nLevel, LPTSTR pszMsg, PVOID pvData, DWORD dwDataSize, DWORD nCols, DWORD dwParams, LPCTSTR pcszFmt, va_list argptr);
        void  InternalTrace(int nLevel, LPTSTR pszMsg, DWORD dwFlags, LPCTSTR pcszFmt, va_list argptr);
        void  InternalTrace(int nLevel, DWORD dwFlags, LPCTSTR pcszFmt, va_list argptr);
        void  InternalTraceStr(int nLevel, LPCTSTR pcszMsg, DWORD dwFlags);
        void  AddPathFromEnvVar(std::string& strPath, LPSTR pszEnvVarName);
        static  BOOL  CALLBACK  EnumLoadedModulesProc ( PSTR pszModuleName, ULONG dwModuleBase, ULONG dwModuleSize, PVOID pUserContext );
        //static  BOOL  CALLBACK  EnumLoadedModulesProc(PTSTR pszModuleName, DWORD64 dwModuleBase, ULONG dwModuleSize, PVOID pUserContext);
        void  SetExtraNesting();
        void  InitializeModule();
        bool  GetSymSearchPath(std::string& strSearchPath);
        void  InitSymHandler();
        bool  GetModuleNameFromAddr(DWORD dwAddr, std::string& strModuleName);
        void  Replace(std::string& str, const std::string& strOld, const std::string& strNew);

        bool  GetTemplArgListPos(std::string& strSymName, DWORD dwPrevPos, DWORD& dwCurPos,
                                 DWORD& dwTmplArgListStartPos, DWORD& dwTmplArgListEndPos);

        //     GetPtrLevel:
        //     Returns the pointer (and references) nesting (indirection) level: 0 for non
        // pointers, 1 for pointers, 2 for pointers to pointers, and so on.
        int  GetPtrLevel(const std::string& strType, DWORD dwTmplArgListEndPos, bool* pbRef = NULL);
        int  TraceStringPtr(DWORD dwInfoFlags, char* pszBuf, DWORD* pdwArg, bool bWide);
        void  TraceStringObjArg(const std::string& strArgType, DWORD dwInfoFlags, DWORD dwTmplArgListEndPos, char* pszBuf, DWORD*& pdwArg, bool bWide, DWORD dwObjSize, DWORD dwOffset, int nPtrLevel = -1);

        bool  IsStringChar(char c);
        bool  IsStringChar(wchar_t c);
        template<class _E> bool  IsValidString(const _E* pcsz);
        std::string  GetArgValue(std::string& strArgType, DWORD dwInfoFlags, DWORD*& pdwArg, DWORD dwTmplArgListStartPos, DWORD& dwTmplArgListEndPos, bool& bUnknown);
        bool  GetSymFromAddr(DWORD dwAddr, DWORD dwStackAddr, DWORD dwInfoFlags, std::string& strSymbol);
        std::string  GetRawDwordList(DWORD*& pdwCurPos, DWORD nDwords, PSTR pszPrefix = "(", PSTR pszPostfix = ")");
        void  ProtectedGetRawDwordList(LPSTR pszArgs, int& nLen, DWORD*& pdwCurPos, DWORD nDwords, PSTR pszPrefix, PSTR pszPostfix);
        BOOL  GetLocationFromAddr(DWORD dwAddr, std::string& strLocation);
        void  TraceStackStr(int nLevel, LPCTSTR pszText);
        BOOL  IntelStackWalk(LPSTACKFRAME psf);
        void  InternalTraceStack(int nLevel, PCONTEXT pCtx, DWORD nExtraNesting, HANDLE hThread, bool bImagehlpStackWalk = true);
        void  InternalTraceStack(int nLevel, DWORD dwFlags, LPCTSTR pcszFmt, va_list argptr);
        std::string  GetCallerFn(DWORD dwInfoFlags, long nExtraNesting = 0);


#if !defined(TRACE_NO_CRASH_REPORT)

        static  PTOP_LEVEL_EXCEPTION_FILTER&  GetPevExceptionFilter();
        LPCTSTR  GetExceptionName(DWORD dwCode);
        void  WriteCrashReportTitle(LPTSTR pszBuf);

        static LONG WINAPI DbgUtilUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo);
#endif // !defined(TRACE_NO_CRASH_REPORT)


    public:
        dbgTracer();
        ~dbgTracer();

        LONG  TraceCrashReport(PEXCEPTION_POINTERS pExceptionInfo, BOOL bKillProcess = FALSE);
        dbgTracer*  SetTraceInfo(LPCTSTR pcszFile, unsigned uLine, DWORD dwFlags);
        void  SetRptOpts(int nLevel, DWORD dwOpts);
        void  SetRptFile(int nLevel, LPCTSTR pcszFile, DWORD dwFileOpts);
        void  SetStackTraceOpts(DWORD dwOpts);
        void  SetMaxTraceLevel(int nLevel);
        void  SetActiveTraceLevel(int nLevel);
        void  SetActiveTraceLevels(int nCount, int* pLevels);
        void  SetComputerCfgInfo(COMPUTER_CFG_INFO fnComputerCfgInfo);
        void  SetCrashRptCallback(CRASHREPORTCALLBACK fnCrashRptCallback);
        void  SetTraceBuffer(LPTSTR pszBuffer, long nBufferSize);
        void  FlushTraceBuffer(int nLevel, LPTSTR pszBuffer, long nCurPos, long nBufferEnd, DWORD dwOpts);
        void  FlushTraceBuffer(int nLevel);
        void  RemoveLastTrace(int nLevel = 0);
        void  Dump(PVOID pvData, DWORD dwDataSize, DWORD dwParams = 0, LPCTSTR pcszFmt = NULL, ...);
        void  Dump(int nLevel, PVOID pvData, DWORD dwDataSize, DWORD dwParams = 0, LPCTSTR pcszFmt = NULL, ...);
        void  DumpTable(PVOID pvData, DWORD dwDataSize, DWORD nCols, DWORD dwParams = 0, LPCTSTR pcszFmt = NULL, ...);
        void  DumpTable(int nLevel, PVOID pvData, DWORD dwDataSize, DWORD nCols, DWORD dwParams = 0, LPCTSTR pcszFmt = NULL, ...);

        void  Trace(int nLevel, LPCTSTR pcszFmt, ...);
        void  TraceStr(int nLevel, LPCTSTR pcszMsg);

        // Trace in Level 0
        void  Trace(LPCTSTR pcszFmt, ...);
        void  TraceStr(LPCTSTR pcszMsg);

        void  TraceStrPrefix(LPCTSTR pcszMsg);
        void  TraceStrPrefix(int nLevel, LPCTSTR pcszMsg);

        void  TraceStack(LPCTSTR pcszFmt = NULL, ...);
        void  TraceStack(int nLevel, LPCTSTR pcszFmt = NULL, ...);
        void  TrAssert(BOOL bExpr, LPCTSTR pcszFmt, ...);
        void  SetTestsSeparator(LPCTSTR pcszTestsSeparatorFmt);
        void  ResetTestNumber();
        void  TraceExpected(LPCTSTR pcszFmt, ...);
        void  TraceResulted(LPCTSTR pcszFmt, ...);

};

}  // end namespace __dbg_util



// this is required 'cause the class must be initialized HERE
// (if you use 'extern' you have to make sure that __dbg_util__dbgTracer is initialized BEFORE all others)
static __dbg_util::dbgTracer __dbg_util__dbgTracer;
//extern __dbg_util::dbgTracer __dbg_util__dbgTracer;






struct  dbgTracer__FileInitializer
{
    dbgTracer__FileInitializer(int nLevel, LPCTSTR pcszFile, DWORD dwOpts)
    {
        __dbg_util__dbgTracer.SetRptFile(nLevel, pcszFile, dwOpts);
    }
};

struct  dbgTracer__OptInitializer
{
    dbgTracer__OptInitializer(int nLevel, DWORD dwOpts)
    {
        __dbg_util__dbgTracer.SetRptOpts(nLevel, dwOpts);
    }
};

struct  dbgTracer__StackTraceOptInitializer
{
    dbgTracer__StackTraceOptInitializer(DWORD dwOpts)
    {
        __dbg_util__dbgTracer.SetStackTraceOpts(dwOpts);
    }
};

struct  dbgTracer__CompCfgInfoInitializer
{
    dbgTracer__CompCfgInfoInitializer(COMPUTER_CFG_INFO fnComputerCfgInfo)
    {
        __dbg_util__dbgTracer.SetComputerCfgInfo(fnComputerCfgInfo);
    }
};

struct  dbgTracer__CrashRptCallbackInitializer
{
    dbgTracer__CrashRptCallbackInitializer(CRASHREPORTCALLBACK fnCrashRptCallback)
    {
        __dbg_util__dbgTracer.SetCrashRptCallback(fnCrashRptCallback);
    }
};



#define  SET_TRACE_FILE(nLevel, pcszFile, dwOpts) static dbgTracer__FileInitializer   __dbg_util__fi__##nLevel(nLevel, pcszFile, dwOpts)
#define  SET_TRACE_OPTS(nLevel, dwOpts)    static dbgTracer__OptInitializer   __dbg_util__oi__##nLevel(nLevel, dwOpts)
#define  SET_STACK_TRACE_OPTS(dwOpts)    static dbgTracer__StackTraceOptInitializer  __dbg_util__sti__(dwOpts)
#define  SET_COMPUTER_CFG_INFO(fnComputerCfgInfo) static  dbgTracer__CompCfgInfoInitializer __dbg_util__ccii__(fnComputerCfgInfo)
#define  SET_CRASH_RPT_CALLBACK(fnCrashRptCallback) static  dbgTracer__CrashRptCallbackInitializer __dbg_util__crci__(fnCrashRptCallback)

#define  TRACE_DEADLOCK(bKillProcess) \
    __dbg_util__dbgTracer.SetTraceInfo(FileLineInfo, 0)->TraceCrashReport(NULL, bKillProcess)

#else  // if  !defined(_DEBUG)  &&  !defined(RELEASE_TRACE)  &&  defined(TRACE_NO_CRASH_REPORT)

#define  SET_TRACE_FILE(nLevel, pcszFile, dwOpts)
#define  SET_TRACE_OPTS(nLevel, dwOpts)
#define  SET_STACK_TRACE_OPTS(dwOpts)
#define  SET_COMPUTER_CFG_INFO(fnComputerCfgInfo)
#define  SET_CRASH_RPT_CALLBACK(fnCrashRptCallback)
#define  TRACE_DEADLOCK(bKillProcess)

#endif  // !defined(_DEBUG)  &&  !defined(RELEASE_TRACE)  &&  defined(TRACE_NO_CRASH_REPORT)









#if defined(_DEBUG)  ||  defined(RELEASE_TRACE)


struct  dbgTracer__TraceLevelInitializer
{
    dbgTracer__TraceLevelInitializer(int nLevel, bool bMax)
    {
        if (bMax)
            __dbg_util__dbgTracer.SetMaxTraceLevel(nLevel);
        else
            __dbg_util__dbgTracer.SetActiveTraceLevel(nLevel);
    }
    dbgTracer__TraceLevelInitializer(int nCount, int* pLevels)
    {
        __dbg_util__dbgTracer.SetActiveTraceLevels(nCount, pLevels);
    }
};

struct  dbgTracer__TraceBufferInitializer
{
    dbgTracer__TraceBufferInitializer(LPTSTR pszBuffer, long nBufferSize)
    {
        __dbg_util__dbgTracer.SetTraceBuffer(pszBuffer, nBufferSize);
    }
};


#define  SET_TRACE_BUFFER(dwLen)  \
    static  TCHAR  __gs__dbg_util__trace_buffer[max(dwLen, MAX_TRACE_MSG_LEN) + MAX_TRACE_MSG_LEN] = { 0 }; \
    static  dbgTracer__TraceBufferInitializer __dbg_util__bi__ (__gs__dbg_util__trace_buffer, max(dwLen, MAX_TRACE_MSG_LEN) + MAX_TRACE_MSG_LEN)

#define  SET_MAX_TRACE_LEVEL(nLevel)    static dbgTracer__TraceLevelInitializer __dbg_util__li__(nLevel, true)
#define  SET_ACTIVE_TRACE_LEVEL(nLevel)    static dbgTracer__TraceLevelInitializer __dbg_util__li__(nLevel, false)
#define  SET_ACTIVE_TRACE_LEVELS(nCount, pLevels) static dbgTracer__TraceLevelInitializer __dbg_util__li__(nCount, pLevels)

#define  FileLineInfo _T(__FILE__), __LINE__

#define  TRACE  __dbg_util__dbgTracer.SetTraceInfo(FileLineInfo, __dbg_util::PfLf)->Trace
#define  ELSE_TRACE else __dbg_util__dbgTracer.SetTraceInfo(FileLineInfo, __dbg_util::PfLf)->Trace
#define  TRACENP __dbg_util__dbgTracer.SetTraceInfo(FileLineInfo, __dbg_util::Lf)->Trace
#define  TRACENL __dbg_util__dbgTracer.SetTraceInfo(FileLineInfo, __dbg_util::Pf)->Trace
#define  TRACENLP __dbg_util__dbgTracer.SetTraceInfo(FileLineInfo, 0)->Trace
#define  TRACENPL __dbg_util__dbgTracer.SetTraceInfo(FileLineInfo, 0)->Trace
#define  TRACERB __dbg_util__dbgTracer.SetTraceInfo(FileLineInfo, __dbg_util::PfLfRb)->Trace
#define  REMOVE_LAST_TRACE __dbg_util__dbgTracer.RemoveLastTrace
#define  TRACESTR __dbg_util__dbgTracer.TraceStr
#define  TRACESTRP __dbg_util__dbgTracer.SetTraceInfo(FileLineInfo, __dbg_util::Pf)->TraceStrPrefix
#define  DUMP  __dbg_util__dbgTracer.SetTraceInfo(FileLineInfo, __dbg_util::Pf)->Dump
#define  DUMPNP  __dbg_util__dbgTracer.SetTraceInfo(FileLineInfo, 0)->Dump
#define  DUMPTBL __dbg_util__dbgTracer.SetTraceInfo(FileLineInfo, __dbg_util::Pf)->DumpTable

#define  TRACE_ARGS   __dbg_util__dbgTracer.SetTraceInfo(FileLineInfo, __dbg_util::PfLf | TraceFnArgsStripped)->Trace
#define  TRACE_ARGS_FULL __dbg_util__dbgTracer.SetTraceInfo(FileLineInfo, __dbg_util::PfLf | TraceFnArgs)->Trace

#define  TRACE_STACK __dbg_util__dbgTracer.SetTraceInfo(FileLineInfo, __dbg_util::PfLf)->TraceStack
#define  TRACE_STACKNP __dbg_util__dbgTracer.SetTraceInfo(FileLineInfo, __dbg_util::Lf)->TraceStack

#define  FLUSH_TRACE_BUFFER(nLevel)  __dbg_util__dbgTracer.FlushTraceBuffer(nLevel);

// Simple testing routines support
#define  SET_TESTS_SEPARATOR(strFmt) __dbg_util__dbgTracer.SetTestsSeparator(strFmt)
#define  RESET_TEST_NUM() __dbg_util__dbgTracer.ResetTestNumber()
#define  EXPECTED   __dbg_util__dbgTracer.SetTraceInfo(FileLineInfo, 0)->TraceExpected
#define  RESULTED   __dbg_util__dbgTracer.SetTraceInfo(FileLineInfo, 0)->TraceResulted
#define  RESULTEDNA   __dbg_util__dbgTracer.SetTraceInfo(FileLineInfo, __dbg_util::DontAssert)->TraceResulted


#else  //if !defined(_DEBUG)  &&  !defined(RELEASE_TRACE)

inline  void __dbg_util__release_Trace(LPCTSTR = 0, ...)  {}
inline  void __dbg_util__release_Trace(int, LPCTSTR = 0, ...)  {}
inline  void __dbg_util__release_RemoveLastTrace(int = 0)  {}
inline  void __dbg_util__release_Dump(PVOID, DWORD, DWORD = 0, LPCTSTR = NULL, ...)  {}
inline  void __dbg_util__release_Dump(int, PVOID, DWORD, DWORD = 0, LPCTSTR = NULL, ...)  {}
inline  void __dbg_util__release_DumpTable(PVOID, DWORD, DWORD, DWORD = 0, LPCTSTR = NULL, ...)  {}
inline  void __dbg_util__release_DumpTable(int, PVOID, DWORD, DWORD, DWORD = 0, LPCTSTR = NULL, ...)  {}

#define  SET_TRACE_BUFFER(dwSize)
#define  FLUSH_TRACE_BUFFER(nLevel)
#define  SET_MAX_TRACE_LEVEL(nLevel)
#define  SET_ACTIVE_TRACE_LEVEL(nLevel)
#define  SET_ACTIVE_TRACE_LEVELS(nCount, pLevels)
#define  TRACE   1 ? (void)0 : __dbg_util__release_Trace
#define  ELSE_TRACE  1 ? (void)0 : __dbg_util__release_Trace
#define  TRACENP  1 ? (void)0 : __dbg_util__release_Trace
#define  TRACENL  1 ? (void)0 : __dbg_util__release_Trace
#define  TRACERB  1 ? (void)0 : __dbg_util__release_Trace
#define  TRACENLP  1 ? (void)0 : __dbg_util__release_Trace
#define  TRACENPL  1 ? (void)0 : __dbg_util__release_Trace
#define  REMOVE_LAST_TRACE 1 ? (void)0 : __dbg_util__release_RemoveLastTrace
#define  TRACESTR  1 ? (void)0 : __dbg_util__release_Trace
#define  TRACESTRP  1 ? (void)0 : __dbg_util__release_Trace
#define  DUMP   1 ? (void)0 : __dbg_util__release_Dump
#define  DUMPNP   1 ? (void)0 : __dbg_util__release_Dump
#define  DUMPTBL  1 ? (void)0 : __dbg_util__release_DumpTable

#define  TRACE_ARGS    1 ? (void)0 : __dbg_util__release_Trace
#define  TRACE_ARGS_STRIPPED 1 ? (void)0 : __dbg_util__release_Trace

#define  TRACE_STACK 1 ? (void)0 : __dbg_util__release_Trace
#define  TRACE_STACKNP 1 ? (void)0 : __dbg_util__release_Trace

// Simple testing routines support
#define  SET_TESTS_SEPARATOR(strFmt)
#define  RESET_TEST_NUM()
#define  EXPECTED   1 ? (void)0 : __dbg_util__release_Trace
#define  RESULTED   1 ? (void)0 : __dbg_util__release_Trace
#define  RESULTEDNA   1 ? (void)0 : __dbg_util__release_Trace

#endif  // !defined(_DEBUG)  &&  !defined(RELEASE_TRACE)


#if defined(_DEBUG)
#define  TRASSERT  __dbg_util__dbgTracer.SetTraceInfo(FileLineInfo, __dbg_util::Lf)->TrAssert
#define  VERIFY(expr) _ASSERTE(expr)
#else
inline  void __dbg_util__release_TrAssert(BOOL, LPCTSTR, ...)  {}
#define  TRASSERT  1 ? (void)0 : __dbg_util__release_TrAssert
#define  VERIFY(expr) ((void)(expr))
#endif  // !_DEBUG

#define  ASSERT   _ASSERTE
#define  ASSERTEX  TRASSERT
#define  RESULTED_  RESULTEDNA


#ifdef DEBUG_SINGLE_HEADER
#include "Debug.cpp"
#endif

